package com.hisense.ovcloud.apicontrol.client;

import cn.hutool.json.JSONUtil;
import com.hisense.ovcloud.apicontrol.config.Constants;
import com.hisense.ovcloud.apicontrol.dto.dto.TokenAuthResult;
import com.hisense.ovcloud.apicontrol.dto.req.GetAppSecretReq;
import com.hisense.ovcloud.apicontrol.dto.req.TokenAuthReq;
import com.hisense.ovcloud.apicontrol.dto.resp.GetAppSecretResp;
import com.hisense.ovcloud.apicontrol.dto.resp.TokenAuthRes;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.time.Duration;

@Component
@Slf4j
public class AuthServiceClient {

    private final WebClient webClient;

    @Value("${authService.url:auth-service:17771}")
    private String authServiceUrl;

    @Value("${http.timeout.seconds:5}")
    private Long TIME_OUT;

    @Value("${http.retry.times:2}")
    private Long RETRY_TIMES;

    public AuthServiceClient(@Qualifier("base") WebClient webClient) {
        this.webClient = webClient;
    }

    //TODO add flag to stop the request
    public Mono<GetAppSecretResp> getAppSecret(GetAppSecretReq req) {
        return webClient.post()
                .uri("http://" + authServiceUrl + "/utils/get_app_secret")
                .body(Mono.just(req), GetAppSecretReq.class)
                .retrieve()
                .bodyToMono(GetAppSecretResp.class)
                .retry(RETRY_TIMES)
                .doOnSuccess(res -> log.info("AuthService-get_app_secret response for appId {}:{}", req.getAppId(), JSONUtil.toJsonStr(res)))
                .doOnError(err -> log.error("request auth-service get_app_secret() method exception for appId {} ", req.getAppId(), err))
                .timeout(Duration.ofSeconds(TIME_OUT));
    }

    public Mono<TokenAuthResult> tokenAuth(TokenAuthReq req) {
        return webClient.post()
                .uri("http://" + authServiceUrl + "/token_auth")
                .body(Mono.just(req), TokenAuthReq.class)
                .retrieve()
                .bodyToMono(TokenAuthRes.class)
                .retry(RETRY_TIMES)
                .doOnSuccess(res -> log.info("tokenAuth accessToken {} success! res: {}", req.getAccessToken(), JSONUtil.toJsonStr(res)))
                .doOnError(err -> log.error("tokenAuth accessToken {} failed! err: {}", req.getAccessToken(), err.getMessage()))
                .timeout(Duration.ofSeconds(TIME_OUT))
                .zipWhen(res -> {
                    if(res.getResultCode() != Constants.RESULT_CODE_SUCCESS){
                        log.warn("tokenAuth accessToken {} failed! errorCode: {}, errorDesc:{}", req.getAccessToken(), res.getErrorCode(), res.getErrorDesc());
                        return Mono.just(
                                TokenAuthResult.builder()
                                        .isSuccess(false)
                                        .errorCode(res.getErrorCode())
                                        .errorDesc(res.getErrorDesc())
                                        .build()
                        );
                    }else{
                        return Mono.just(
                                TokenAuthResult.builder()
                                .isSuccess(true)
                                .appid(res.getClientId())
                                .platformId(res.getPlatformId())
                                .customerId(res.getCustomerId())
                                .tokenType(res.getTokenType())
                                .tenantId(res.getTenantId())
                                .build());
                    }
                }, (x, y) -> y);
    }
}

